package jxtend.processor.eclipse.utils;

import jxtend.processor.exception.JxtendProcessorException;

import org.eclipse.jdt.internal.compiler.ast.ASTNode;

@SuppressWarnings("restriction")
public enum ASTNodeKind {
	NORMAL("org.eclipse.jdt.internal.compiler.ast", ""),
	SELECTION("org.eclipse.jdt.internal.codeassist.select", "SelectionOn"),
	COMPLETION("org.eclipse.jdt.internal.codeassist.complete", "CompletionOn"),
	CODE_SNIPPET("org.eclipse.jdt.internal.eval", "CodeSnippet");

	private final String packageName;
	private final String classNamePrefix;	

	private ASTNodeKind(String packageName, String classNamePrefix) {
		this.packageName = packageName;
		this.classNamePrefix = classNamePrefix;
	}

	public <T> Class<T> getClassForKind(Class<T> astNodeClassForNormalKind) {
		return getClassForKind(astNodeClassForNormalKind, "");
	}

	@SuppressWarnings("unchecked")
	public <T> Class<T> getClassForKind(Class<T> astNodeClassForNormalKind, String classNamePostfix) {
		if (!astNodeClassForNormalKind.getPackage().getName().equals(NORMAL.packageName)) {
			throw new IllegalArgumentException("Supplied class it not a proper class for normal kind of AST node: "
					+ astNodeClassForNormalKind.getClass().getName());
		}

		try {
			String fullyQualifiedClassName =
				packageName + "." + classNamePrefix + astNodeClassForNormalKind.getSimpleName() + classNamePostfix;

			return (Class<T>) ASTNodeKind.class.getClassLoader().loadClass(fullyQualifiedClassName);
		} catch (ClassNotFoundException e) {
			throw new JxtendProcessorException(e);
		}
	}
	
	public static ASTNodeKind getEnum(ASTNode astNode) {
		for (ASTNodeKind enumInstance : ASTNodeKind.values()) {
			if (enumInstance.packageName.equals(astNode.getClass().getPackage().getName())) {
				return enumInstance;
			}
		}

		throw new IllegalArgumentException("Code not determine kind for AST node: " + astNode);
	}
}
